package com.battery.system.service.battery.impl;

import java.math.BigDecimal;
import java.util.List;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.battery.common.enums.*;
import com.battery.common.utils.BatteryJSONResult;
import com.battery.common.utils.Constants;
import com.battery.common.utils.DateUtils;
import com.battery.common.utils.GenerateSeqUtil;
import com.battery.common.utils.ali.AliPayEntity;
import com.battery.common.utils.ali.AliPayUtils;
import com.battery.system.domain.*;
import com.battery.system.mapper.*;
import com.battery.system.service.ISysConfigService;
import com.battery.system.service.battery.IIncomeService;
import com.battery.system.service.impl.BaseServiceImpl;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import org.apache.commons.lang3.StringUtils;
import org.n3r.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.battery.system.service.battery.IRefundOrderService;
import com.battery.common.core.text.Convert;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

/**
 * 退款订单Service业务层处理
 *
 * @author battery
 * @date 2021-01-22
 */
@Service
public class RefundOrderServiceImpl extends BaseServiceImpl<RefundOrder> implements IRefundOrderService {

    @Autowired
    private RefundOrderMapper refundOrderMapper;

    @Autowired
    private Sid sid;


    @Autowired
    private RefundApplyMapper refundApplyMapper;


    //  微信支付
    @Autowired(required = false)
    private WxPayService wxService;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UsedMapper usedMapper;

    @Autowired
    private AppUserMapper appUserMapper;


    @Autowired
    private IIncomeService incomeService;

    @Autowired
    private ISysConfigService configService;

    /**
     * 查询退款订单
     *
     * @param id 退款订单ID
     * @return 退款订单
     */
    @Override
    public RefundOrder selectRefundOrderById(String id) {
        return refundOrderMapper.selectRefundOrderById(id);
    }

    /**
     * 查询退款订单列表
     *
     * @param refundOrder 退款订单
     * @return 退款订单
     */
    @Override
    public List<RefundOrder> selectRefundOrderList(RefundOrder refundOrder) {
        return refundOrderMapper.selectRefundOrderList(refundOrder);
    }

    /**
     * 新增退款订单
     *
     * @param refundOrder 退款订单
     * @return 结果
     */
    @Override
    public int insertRefundOrder(RefundOrder refundOrder) {
        refundOrder.setCreateTime(DateUtils.getNowDate());
        return refundOrderMapper.insertRefundOrder(refundOrder);
    }

    /**
     * 修改退款订单
     *
     * @param refundOrder 退款订单
     * @return 结果
     */
    @Override
    public int updateRefundOrder(RefundOrder refundOrder) {
        return refundOrderMapper.updateRefundOrder(refundOrder);
    }

    /**
     * 删除退款订单对象
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteRefundOrderByIds(String ids) {
        return refundOrderMapper.deleteRefundOrderByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除退款订单信息
     *
     * @param id 退款订单ID
     * @return 结果
     */
    @Override
    public int deleteRefundOrderById(String id) {
        return refundOrderMapper.deleteRefundOrderById(id);
    }

    /**
     * 微信小程序用户退押操作
     *
     * @param appUser       用户信息
     * @param noUsedDeposit 微信用户押金
     * @param refund_fee    退押金额
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult wxRefundDeposit(AppUser appUser, Order noUsedDeposit, BigDecimal refund_fee) {
        // 查询该笔押金是否已存在对应的退款订单
        Example example = new Example(RefundOrder.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("orderId", noUsedDeposit.getId());
        criteria.andEqualTo("refundStatus", RefundStatusEnum.CHANGE.getCode()); // 退款异常
        RefundOrder errRefund = refundOrderMapper.selectOneByExample(example);
        String out_refund_no = ""; // 退款单号
        String refundOrderId = null;
        if (errRefund != null) {
            // 存在退款异常的订单
            // 存在错误的退款订单，那么采用错误的退款订单来进行操作
            out_refund_no = errRefund.getOutRefundNo();
            RefundOrder orderUpdate = new RefundOrder();
            orderUpdate.setId(errRefund.getId());
            orderUpdate.setRefundFee(refund_fee);
            orderUpdate.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
            refundOrderMapper.updateByPrimaryKeySelective(orderUpdate);
            refundOrderId = errRefund.getId();
        } else {
            // 退款单号
            out_refund_no = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);
            RefundOrder refundOrder = new RefundOrder();
            refundOrder.setId(sid.nextShort());
            refundOrder.setAppUserId(appUser.getId());
            refundOrder.setOutRefundNo(out_refund_no);
            refundOrder.setTotalFee(noUsedDeposit.getTotalFee());
            refundOrder.setRefundFee(refund_fee);
            refundOrder.setRefundDesc("用户退押金");
            refundOrder.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
            refundOrder.setCreateTime(DateUtils.getNowDate());
            refundOrder.setOrderId(noUsedDeposit.getId());
            refundOrder.setOrderType(noUsedDeposit.getOrderType());
            refundOrder.setChannel(noUsedDeposit.getChannel());
            refundOrderMapper.insertSelective(refundOrder);
            // 查询新建的退款数据
            refundOrderId = refundOrder.getId();
        }
        // 发起退款操作
        WxPayRefundRequest refundRequest = new WxPayRefundRequest();
        refundRequest.setTransactionId(noUsedDeposit.getTransactionId());
        refundRequest.setOutRefundNo(out_refund_no);
        refundRequest.setTotalFee(noUsedDeposit.getTotalFee().multiply(new BigDecimal(100)).intValue());
        refundRequest.setRefundFee(refund_fee.multiply(new BigDecimal(100)).intValue());
        refundRequest.setNotifyUrl(Constants.wx_refund_callback_url); // 退款通知接口
        WxPayRefundResult refundResult = null;
        boolean flag = false;
        try {
            refundResult = wxService.refund(refundRequest);
        } catch (WxPayException e) {
            // 发生错误
            e.printStackTrace();
            flag = true;
        }
        if (refundResult == null || flag) {
            // 调起微信退款接口发生错误
            RefundOrder updateRefundOrder = new RefundOrder();
            updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
            updateRefundOrder.setId(refundOrderId);
            updateRefundOrder.setRemark("发起退押出现异常");
            refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);

            return BatteryJSONResult.errorMsg("发起退押出现异常");
        }
        String return_code = refundResult.getReturnCode();
        String result_code = refundResult.getResultCode();
        if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) {
            // 发起退款接口成功，更新退款订单号
            String refund_id = refundResult.getRefundId(); // 微信退款单号
            RefundOrder updateOrder = new RefundOrder();
            updateOrder.setId(refundOrderId);
            updateOrder.setRefundId(refund_id);
            refundOrderMapper.updateRefundOrder(updateOrder);

            // 更新原先订单状态
            Order updateFormer = new Order();
            updateFormer.setId(noUsedDeposit.getId());
            updateFormer.setTradeState(OrderTradeStateEnum.TO_REFUND.getCode()); // 转入退款
            updateFormer.setRefundId(out_refund_no); // 退款订单号
            updateFormer.setRefundMoney(refund_fee); // 退款金额
            orderMapper.updateByPrimaryKeySelective(updateFormer);
            return BatteryJSONResult.ok();
        }
        // 调起微信退款接口发生错误
        RefundOrder updateRefundOrder = new RefundOrder();
        updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
        updateRefundOrder.setId(refundOrderId);
        updateRefundOrder.setRemark("发起退押出现异常");
        refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
        return BatteryJSONResult.errorMsg("退押失败,微信返回【" + refundResult.getErrCodeDes() + "】"); // 返回错误描述
    }

    /**
     * 根据退款订单号查询对应的退款信息
     *
     * @param out_refund_no
     * @return
     */
    @Override
    public RefundOrder selectByOutRefundNo(String out_refund_no) {

        Example example = new Example(RefundOrder.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("outRefundNo", out_refund_no);
        return refundOrderMapper.selectOneByExample(example);
    }

    /**
     * 退款回调处理
     *
     * @param refundOrder 退款订单
     * @param reqInfo     退款回调信息
     * @return
     */
    @Transactional
    @Override
    public int operationWxRefundNotify(RefundOrder refundOrder, WxPayRefundNotifyResult.ReqInfo reqInfo) {
        RefundOrder updateRefundOrder = new RefundOrder();
        updateRefundOrder.setId(refundOrder.getId());
        // SUCCESS-退款成功，CHANGE-退款异常，REFUNDCLOSE—退款关闭
        String refundStatus = reqInfo.getRefundStatus();
        boolean flag = false;
        if ("SUCCESS".equals(refundStatus)) {
            // 退款成功
            updateRefundOrder.setRefundStatus(RefundStatusEnum.SUCCESS.getCode());
            flag = true;
        } else if ("CHANGE".equals(refundStatus)) {
            // 退款异常
            updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode());
        } else if ("REFUNDCLOSE".equals(refundStatus)) {
            // 退款关闭
            updateRefundOrder.setRefundStatus(RefundStatusEnum.REFUNDCLOSE.getCode());
        }
        updateRefundOrder.setSuccessTime(DateUtils.parseDate(reqInfo.getSuccessTime()));
        updateRefundOrder.setRefundRecvAccout(reqInfo.getRefundRecvAccout()); // 退款入账账户
        // 更新退款订单
        refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
        // 查询支付订单
        boolean isRefundIncome = false;
        Order order = orderMapper.selectByPrimaryKey(refundOrder.getOrderId());
        if (flag) {
            // 退款失败的订单，对应的支付订单不更新
            // 退款成功，进行业务处理
            // 更新支付订单状态
            Order orderUpdate = new Order();
            orderUpdate.setId(refundOrder.getOrderId());
            orderUpdate.setTradeState(OrderTradeStateEnum.REFUND_SUCCESS.getCode());
            orderUpdate.setRefundTime(updateRefundOrder.getSuccessTime()); // 退款成功时间
            orderMapper.updateByPrimaryKeySelective(orderUpdate);
            if (OrderTypeEnum.DEPOSIT.type.equals(order.getOrderType())) {
                // 押金租借订单退款
                if (order.getIsUsed() == 1) {
                    if (StringUtils.isNotBlank(order.getUsedId())) {
                        Used used = usedMapper.selectByPrimaryKey(order.getUsedId());
                        // 押金已使用完毕，则代表用户是99元扣款，直接扣除押金
                        Used usedUpdate = new Used();
                        usedUpdate.setId(used.getId());
                        usedUpdate.setStatus(UsedStatusEnum.REFUND_SUCCESS.getCode());
                        usedMapper.updateByPrimaryKeySelective(usedUpdate);
                        // TODO TODO 退款成功 退款分润
                        isRefundIncome = true;
                    }
                } else {
                    // 押金并没有使用完毕，那么先查询是否存在未支付的订单，如果存在，则设置为已支付
//                    Example example = new Example(Used.class);
//                    Example.Criteria criteria = example.createCriteria();
//                    criteria.andEqualTo("leaseState", LeaseStateEnum.SUCCESS.getCode()); // 租借成功
//                    criteria.andEqualTo("isBack", YesOrNoEnum.YES.getCode()); // 归还成功
//                    criteria.andEqualTo("appUserId", order.getAppUserId());
//                    criteria.andEqualTo("channel", order.getChannel());
//                    criteria.andEqualTo("borrowMode", BorrowModeEnum.DEPOSIT.type);
//                    criteria.andEqualTo("status", UsedStatusEnum.TO_BE_PAID.getCode()); // 待支付
//                    example.orderBy("createTime").desc();
                    Used noPayUsed = usedMapper.selectByPrimaryKey(order.getUsedId());
                    if (noPayUsed != null) {

                        // 存在未付款的订单
                        Used usedUpdate = new Used();
                        usedUpdate.setId(noPayUsed.getId());
                        usedUpdate.setStatus(UsedStatusEnum.PAID.getCode()); // 设置为已支付
                        usedUpdate.setTrueOrderId(order.getId()); // 真实支付ID 为 押金订单ID
                        usedMapper.updateByPrimaryKeySelective(usedUpdate);
//                        int autoRefundYj = Integer.parseInt(configService.selectConfigByKeyNoCache("sys.borrow.autoRefundYj"));
//                        if (autoRefundYj == 0) {
//                            // 不自动退押金，更新用户余额
//                            AppUser appUser = appUserMapper.selectAppUserById(order.getAppUserId());
//                            AppUser userUpdate = new AppUser();
//                            userUpdate.setId(appUser.getId());
//                            userUpdate.setBalance(appUser.getBalance().add(noPayUsed.getAmountPaid()));
//                            appUserMapper.updateAppUser(userUpdate);
//                        }
                        // TODO TODO TODO 退款成功，需要对原先存在欠款的订单进行分润
                        try {
                            incomeService.shareMoney(noPayUsed.getId(), order.getId()); // 押金退款，如果退部分的话，之后已经是不能在退了
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            } else {
                // 机柜租借费用，线租借费用
                if (StringUtils.isNotBlank(order.getUsedId())) {
                    Used usedUpdate = new Used();
                    usedUpdate.setId(order.getUsedId());
                    usedUpdate.setStatus(UsedStatusEnum.REFUND_SUCCESS.getCode());
                    RefundOrder refundOrderNew = refundOrderMapper.selectByPrimaryKey(refundOrder.getId());
                    usedUpdate.setRefundAmount(refundOrderNew.getRefundFee());
                    usedMapper.updateByPrimaryKeySelective(usedUpdate);
                    // TODO TODO 退款成功 退款分润
                    isRefundIncome = true;
                }
            }
            if (isRefundIncome) {
                Example example = new Example(RefundApply.class);
                Example.Criteria criteria = example.createCriteria();
                criteria.andEqualTo("usedId", order.getUsedId());
                criteria.andEqualTo("auditStatus", 2);
                example.orderBy("createdTime").desc();
                List<RefundApply> refundApplys = refundApplyMapper.selectByExample(example);
                if (refundApplys != null && refundApplys.size() > 0) {
                    RefundApply refundApply = refundApplys.get(0);
                    RefundApply refundApplyUpdate = new RefundApply();
                    refundApplyUpdate.setId(refundApply.getId());
                    refundApplyUpdate.setRefundStatus(2); // 退款成功
                    refundApplyMapper.updateByPrimaryKeySelective(refundApplyUpdate);
                }
                // TODO TODO 退款成功 退款分润
                try {
                    incomeService.refundShareMoney(order.getUsedId(), order.getId(), refundOrder.getId());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return 1;
    }

    /**
     * 支付宝退押金
     *
     * @param appUser
     * @param noUsedDeposit
     * @param refund_fee
     * @param entity
     * @return
     */
    @Transactional
    @Override
    public BatteryJSONResult aliRefundDeposit(AppUser appUser, Order noUsedDeposit, BigDecimal refund_fee, AliPayEntity entity) {

        Example example = new Example(RefundOrder.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("orderId", noUsedDeposit.getId());
        criteria.andEqualTo("refundStatus", RefundStatusEnum.CHANGE.getCode()); // 退款异常
        RefundOrder errRefund = refundOrderMapper.selectOneByExample(example);

        String out_refund_no = ""; // 退款单号
        String refundOrderId = null;
        if (errRefund != null) {
            // 存在退款异常的订单
            // 存在错误的退款订单，那么采用错误的退款订单来进行操作
            out_refund_no = errRefund.getOutRefundNo();
            RefundOrder orderUpdate = new RefundOrder();
            orderUpdate.setId(errRefund.getId());
            orderUpdate.setRefundFee(refund_fee);
            orderUpdate.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
            refundOrderMapper.updateByPrimaryKeySelective(orderUpdate);

            refundOrderId = errRefund.getId();
        } else {
            out_refund_no = GenerateSeqUtil.generateEndRadomCode() + GenerateSeqUtil.getRandomCode(6);

            RefundOrder refundOrder = new RefundOrder();
            refundOrder.setId(sid.nextShort());
            refundOrder.setAppUserId(appUser.getId());
            refundOrder.setOutRefundNo(out_refund_no);
            refundOrder.setTotalFee(noUsedDeposit.getTotalFee());
            refundOrder.setRefundFee(refund_fee);
            refundOrder.setRefundDesc("用户退押金");
            refundOrder.setRefundStatus(RefundStatusEnum.REQUEST_REFUND.getCode()); // 发起退款
            refundOrder.setCreateTime(DateUtils.getNowDate());
            refundOrder.setOrderId(noUsedDeposit.getId());
            refundOrder.setOrderType(noUsedDeposit.getOrderType());
            refundOrder.setChannel(noUsedDeposit.getChannel());
            refundOrderMapper.insertSelective(refundOrder);

            // 查询新建的退款数据
            refundOrderId = refundOrder.getId();
        }
        // 发起退款操作
        JSONObject requestRefundObj = new JSONObject();
        requestRefundObj.put("out_trade_no", noUsedDeposit.getOutOrderNo());
        requestRefundObj.put("trade_no", noUsedDeposit.getTransactionId());
        requestRefundObj.put("out_request_no", out_refund_no);
        requestRefundObj.put("refund_amount", refund_fee);
        BatteryJSONResult result = null;
        boolean flag = false;
        try {
            result = AliPayUtils.tradeRefund(entity, requestRefundObj);
        } catch (Exception e) {
            e.printStackTrace();
            flag = true;
        }
        if (result == null || flag) {
            // 支付宝退款抛出异常
            RefundOrder updateRefundOrder = new RefundOrder();
            updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
            updateRefundOrder.setId(refundOrderId);
            updateRefundOrder.setRemark("发起退押出现异常");
            refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
            return BatteryJSONResult.errorMsg("发起退押出现异常");
        }
        AlipayTradeRefundResponse response = (AlipayTradeRefundResponse) result.getData();
        if (response.isSuccess()) {
            // 退款成功
            RefundOrder updateOrder = new RefundOrder();
            updateOrder.setId(refundOrderId);
            updateOrder.setRefundStatus(RefundStatusEnum.SUCCESS.getCode());
            updateOrder.setSuccessTime(DateUtils.getNowDate());
            refundOrderMapper.updateByPrimaryKeySelective(updateOrder);

            // 更新原先订单状态
            Order updateFormer = new Order();
            updateFormer.setId(noUsedDeposit.getId());
            updateFormer.setTradeState(OrderTradeStateEnum.REFUND_SUCCESS.getCode()); // 直接更新状态为退款成功
            updateFormer.setRefundId(out_refund_no); // 退款订单号
            updateFormer.setRefundMoney(refund_fee); // 退款金额
            orderMapper.updateByPrimaryKeySelective(updateFormer);

            // TODO TODO
            // 押金并没有使用完毕，那么先查询是否存在未支付的订单，如果存在，则设置为已支付
            Example exampleUsed = new Example(Used.class);
            Example.Criteria criteriaUsed = exampleUsed.createCriteria();
            criteriaUsed.andEqualTo("leaseState", LeaseStateEnum.SUCCESS.getCode()); // 租借成功
            criteriaUsed.andEqualTo("isBack", YesOrNoEnum.YES.getCode()); // 归还成功
            criteriaUsed.andEqualTo("appUserId", appUser.getId());
            criteriaUsed.andEqualTo("channel", noUsedDeposit.getChannel());
            criteriaUsed.andEqualTo("borrowMode", BorrowModeEnum.DEPOSIT.type);
            criteriaUsed.andEqualTo("status", UsedStatusEnum.TO_BE_PAID.getCode()); // 待支付
            exampleUsed.orderBy("createTime").desc();
            Used noPayUsed = usedMapper.selectOneByExample(exampleUsed);
            if (noPayUsed != null) {
                // 存在未付款的订单
                Used usedUpdate = new Used();
                usedUpdate.setId(noPayUsed.getId());
                usedUpdate.setStatus(UsedStatusEnum.PAID.getCode()); // 设置为已支付
                usedUpdate.setTrueOrderId(noUsedDeposit.getId()); // 真实支付ID 为 押金订单ID
                usedMapper.updateByPrimaryKeySelective(usedUpdate);

                // 更新用户余额
                AppUser userUpdate = new AppUser();
                userUpdate.setId(appUser.getId());
                userUpdate.setBalance(appUser.getBalance().add(noPayUsed.getAmountPaid()));
                appUserMapper.updateByPrimaryKeySelective(userUpdate);

                // TODO TODO 支付宝退款之后，需要调起分润操作
                try {
                    incomeService.shareMoney(noPayUsed.getId(), null);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
            return BatteryJSONResult.ok();
        }

        RefundOrder updateRefundOrder = new RefundOrder();
        updateRefundOrder.setRefundStatus(RefundStatusEnum.CHANGE.getCode()); // 退款异常
        updateRefundOrder.setId(refundOrderId);
        updateRefundOrder.setRemark("发起退押出现异常");
        refundOrderMapper.updateByPrimaryKeySelective(updateRefundOrder);
        return BatteryJSONResult.errorMsg("退押失败,支付宝返回【" + response.getSubMsg() + "】"); // 返回错误描述
    }
}
